package com.lyx.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lyx.common.config.SystemConfig;
import com.lyx.common.param.UserCouponAdd;
import com.lyx.common.vo.R;
import com.lyx.server.dao.CouponDao;
import com.lyx.server.dao.CouponLogDao;
import com.lyx.server.dao.UserCouponDao;
import com.lyx.server.entity.Coupon;
import com.lyx.server.entity.CouponLog;
import com.lyx.server.entity.UserCoupon;
import com.lyx.server.redisson.RedissonUtil;
import com.lyx.server.service.UserCouponService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.lyx.common.config.RedisKeyConfig;

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * ⽤户优惠券表(UserCoupon)表服务实现类
 *
 * @author McMeloxD
 * @since 2024-08-14 18:13:23
 */
@Service("userCouponService")
@RequiredArgsConstructor
public class UserCouponServiceImpl implements UserCouponService {
    private final UserCouponDao dao;
    private final CouponDao couponDao;
    private final CouponLogDao logDao;


    @Transactional // 开事务
    @Override
    public R save(UserCouponAdd add) {
        // 1.校验
        if (add == null) {
            return R.fail("亲，请检查参数信息");
        }
        // 2.查询 用户是否已经领过
        UserCoupon userCoupon = dao.selectOne(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUid, add.getUid()).eq(UserCoupon::getCid, add.getCid()));
        if (userCoupon != null) {
            // 之前领取过
            return R.fail("亲，你已经领取过了！");
        }
        // 3.获取分布式锁
        RLock lock = RedissonUtil.getLock(RedisKeyConfig.COUPON_LOCK + add.getCid());
        // 尝试加锁,同时设置超时的时间，防止出现问题不会自动释放
        try {
            if (lock.tryLock(3, TimeUnit.SECONDS)) {
                // 4.查询对应的优惠券
                Coupon coupon = couponDao.selectById(add.getCid());
                System.out.println("优惠券信息：" + coupon);
                if (coupon == null) {
                    return R.fail("亲，优惠券不存在！");
                }
                // 验证优惠券状态
                if (!coupon.getStatus().equals("审核通过")) {
                    return R.fail("亲，优惠券已失效！");
                }
                // 5.验证 优惠券数量
                if (coupon.getNum() > 0) {
                    // 优惠券，如果不限制数量 num=0,num>0 说明有限制 就不能超领
                    if (coupon.getNum() - coupon.getTakenum() <= 0) {
                        return R.fail("亲，来晚了，已被领完！");
                    }
                }

                // 6.创建对象，新增到数据库
                userCoupon = new UserCoupon();
                userCoupon.setCid(add.getCid());
                userCoupon.setUid(add.getUid());
                userCoupon.setMoney(coupon.getMoney());
                userCoupon.setUsemoney(coupon.getUsemoney());
                userCoupon.setType(coupon.getType());
                userCoupon.setStartDate(new Date());
                // 获取日历对象 用于计算日期 计算优惠券的失效日期
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.DAY_OF_MONTH, coupon.getDays());
                userCoupon.setEndDate(calendar.getTime());
                userCoupon.setMoney(coupon.getMoney());
                userCoupon.setStatus("未使用");
                userCoupon.setCreateTime(new Date());
                userCoupon.setUpdateTime(new Date());
                if (dao.insert(userCoupon) <= 0) {
                    return R.fail("亲，领取失败！");
                }
                // 7.修改优惠券领取的数量
                couponDao.updateTakeNum(add.getCid());

                // 8.记录优惠券操作日志
                logDao.insert(new CouponLog(add.getUid(), userCoupon.getCid(), coupon.getMoney(), "领取优惠券", "领取" + coupon.getTitle() + "成功"));

                // 9.释放分布式锁
                lock.unlock();

                return R.ok("");
            }
            //     这里必须使用子异常, 否则会抛出异常导致事务回滚出现问题,这里只是为了让分布式锁捕获异常
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return R.fail("亲，领取失败");
    }

    @Override
    public R queryByUid(Integer uid) {
        return R.ok(dao.selectDetail(uid));
    }

    /*
    * 注册新用户送优惠券
    * */
    @Transactional
    @Override
    public int saveNew(Integer uid) {
        int r=0;
        for (Integer id: SystemConfig.newids) {
            // 判断优惠券的状态
            if (couponDao.selectById(id).getStatus().equals("审核通过")){
                Coupon coupon=couponDao.selectById(id);
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.DAY_OF_MONTH, coupon.getDays());
                UserCoupon userCoupon=new UserCoupon(uid,coupon.getId(),coupon.getMoney(),coupon.getUsemoney(),calendar.getTime(),coupon.getType());
                r+=dao.insert(userCoupon);
                logDao.insert(new CouponLog(uid, coupon.getId(), coupon.getMoney(), "新用户奖励优惠券", "注册成为新用户，奖励" + coupon.getTitle() + "成功"));
                couponDao.updateTakeNum(coupon.getId());
            }
        }
        return r;
    }

    /*
     * 邀请新用户送优惠券
     * */
    @Transactional
    @Override
    public int saveAsk(Integer uid) {
        int r=0;
        for (Integer id: SystemConfig.askids) {
            Coupon coupon=couponDao.selectById(id);
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, coupon.getDays());
            UserCoupon userCoupon=new UserCoupon(uid,coupon.getId(),coupon.getMoney(),coupon.getUsemoney(),calendar.getTime(),coupon.getType());
            r+=dao.insert(userCoupon);
            logDao.insert(new CouponLog(uid, coupon.getId(), coupon.getMoney(), "邀请新用户奖励优惠券", "邀请新用户，奖励" + coupon.getTitle() + "成功"));
            couponDao.updateTakeNum(coupon.getId());
        }
        return r;
    }
}

